package org.example;

import com.scm.all.export.*;
import com.scm.all.pfunc.ResponseEventCallBack;
import com.scm.x64.export.MemoryOperationUtilsX64;

import java.awt.*;
import java.awt.event.InputEvent;
import java.util.ArrayList;
import java.util.List;

/**
 * 版权蜗牛猫软件开发工作室
 * QQ连连看角色版  必须位于屏幕的左上角 0,0的位置否则无效！ 必须窗口在前
 *
 * QQ连连看参考地址：
 * https://blog.csdn.net/Kizuna_AI/article/details/81121489?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%2281121489%22%2C%22source%22%3A%22unlogin%22%7D
 * https://blog.csdn.net/u011081622/article/details/130754176
 * https://blog.csdn.net/zhelong19830726/article/details/98394184?ydreferer=aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwODE2MjIvYXJ0aWNsZS9kZXRhaWxzLzEzMDc1NDE3Ng%3D%3D
 *
 */
public class App {

    //搜索的标记及其方向，不懂的可以查一查BFS（广度优先搜索）
    public static int bfFlag = 0;
    public static boolean isOk = false;
    public static int[][] dirary = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
//    起始点 X
    public static int block_x = 31;
//    起始点 Y
    public static int block_y = 35;

    public static int left_x = 13;
    public static int left_y = 180;
    public static Robot s = null;
//    块元素身份数据
    public static List<BlockData> attr = new ArrayList<BlockData>();
    public static void main(String[] args) {
//        System.out.println();
        PathFileJSCM.setDebugFile32(PathFileJSCM.getJarPath()+"sdk\\x86\\");
        PathFileJSCM.setDebugFile64(PathFileJSCM.getJarPath()+"sdk\\x64\\");
//        PathFileJSCM.setDebugFile32("C:\\Users\\www10\\IdeaProjects\\scmJnaApi\\Application\\JscmOneToOne\\Jscm框架完整附属包V1.1.2\\x86\\");
//        PathFileJSCM.setDebugFile64("C:\\Users\\www10\\IdeaProjects\\scmJnaApi\\Application\\JscmOneToOne\\Jscm框架完整附属包V1.1.2\\x64\\");
        PathFileJSCM.setIsDebug(false);

        try {
            s = new Robot();
        } catch (AWTException e) {
            e.printStackTrace();
        }


//        棋盘数基址："python24.dll"+001C616C+DC0   00184DC0
//        棋盘类型基址："kyodaiRPG.exe"+00094C00+40  00199F5C
//        进程是否存在
        if (ProcessAndThreadUtils.processNameIsTrue("QQGame.exe")) {
//            监视热键  F6键自动消除
            SystemUtils.listeningHotKeyOne(new ResponseEventCallBack() {
                @Override
                public void callback() {
                    if (ProcessAndThreadUtils.processNameIsTrue("kyodaiRPG.exe")) {
                        int pid = ProcessAndThreadUtils.processNameGetPid("kyodaiRPG.exe");
                        //打开进程
                        int openProcess = ProcessAndThreadUtils.openProcess(pid);
                        int handle = WindowOperationUtils.windowGetHwndTow(ProcessAndThreadUtils.processNameGetPid("kyodaiRPG.exe"),"#32770","QQ游戏 - 连连看角色版");
                        WindowOperationUtils.windowTop(handle,-1,0x0001);
                        WindowOperationUtils.windowAlwaysTop(handle,true);
                        WindowOperationUtils.windowActivation(handle);
                        WindowOperationUtils.windowSetLocationSize(handle,-10,-1,WindowOperationUtils.windowGetRectToSize(handle).width,WindowOperationUtils.windowGetRectToSize(handle).height);
                        lineBlock(openProcess, s);//核心的算法
                        ProcessAndThreadUtils.closeHandle(openProcess);//关闭句柄
                    }else {
                        System.out.println("进程不存在：QQ连连看-角色版");
                    }

                }
            },117,0);
//            do{
//                //            获取棋盘字节
//                size = MemoryOperationUtilsX64.readProcessMemoryByte(openProcess, ByteUtils.hexStrToInt1("00184DC0"), 4);
//                lineBlock(openProcess, s);
//            }while (ByteUtils.bytesArrayToInt(size)!=0 && size.length != 0);
        } else {
            System.out.println("进程不存在：QQ游戏");
        }
    }


    public static void lineBlock(int openProcess, Robot s) {
//            获取棋盘类型
        byte[] data = MemoryOperationUtilsX64.readProcessMemoryByte(openProcess, ByteUtils.hexToLong1("00199F5C"), 19 * 11);
//        System.out.println("棋盘数据：" + ByteUtils.bytesToHexString(data));


//            新建二维数组
        byte[][] xyData = new byte[11][19];
//            棋盘数组矩阵
        int index = 0;
        for (int i = 0; i < xyData.length; i++) {
            for (int j = 0; j < xyData[i].length; j++) {
                xyData[i][j] = data[index++];
            }
        }
//        集合清空
        attr.clear();
//            从左到右枚举
        for (int i = 0; i < 11; i++) {
            for (int j = 0; j < 19; j++) {
                if (xyData[i][j] == 0) {
                    continue;
                }
//            从右到左枚举
                for (int k = i; k < 11; k++) {
                    for (int l = 0; l < 19; l++) {
                        if (xyData[k][l] == 0) {
                            continue;
                        }
                        if (k == i && l == j && xyData[i][j] == xyData[k][l]) {
                            BlockData blockData = new BlockData();
                            blockData.setI(i);
                            blockData.setJ(j);
                            blockData.setK(k);
                            blockData.setL(l);
                            blockData.setDat(xyData);
                            blockData.setData(xyData[i][j]);
                            xyData[i][j] = 1;
                            bfFlag = 0;
                            isOk = false;
                            bfs(i, j, k, l, xyData, 0, 0);
                            if (isOk) {
                                int x = (left_x + j * block_x) + 10;
                                int y = (left_y + i * block_y) + 10;
                                blockData.setX(x);
                                blockData.setY(y);
                                attr.add(blockData);
                            }
                        }
                    }
                }
            }
        }
        for(BlockData a :attr){
            for(BlockData b :attr){
                if(a.getData() == b.getData()){
                    int ret = can_remove(a.getI(),a.getJ(),b.getK(),b.getL(),xyData);
                    if(ret != 0){
                        moves(s,a.getX(),a.getY());
                        moves(s,b.getX(),b.getY());
                    }

                }
            }
        }


    }

    public static void moves(Robot s,int x,int y){
        s.mouseMove(x, y);
        s.mousePress(InputEvent.BUTTON1_DOWN_MASK);
        s.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
        sleeps();
    }

    public static void sleeps() {
        try {
            Thread.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void bfs(int i, int j, int k, int l, byte[][] data, int dir, int temp) {
        if (bfFlag == 1) {
            return;
        }
        if (temp > 2) {
            return;
        }
        if ((i == k) && (j == l)) {
            bfFlag = 1;
            isOk = true;
            return;
        }
        for (int n = 0; n < 4; n++) {
            int x = i + dirary[n][0];
            int y = j + dirary[n][1];
            if (x < 0 || x > 10 || y < 0 || y > 18 || data[x][y] == 1) {
                continue;
            }
            data[x][y] = 1;
            if (dir == 0) {
                bfs(x, y, k, n, data, n + 1, temp);
            } else {
                if (n + 1 != dir) {
                    bfs(x, y, k, n, data, n + 1, temp + 1);
                } else {
                    bfs(x, y, k, n, data, n + 1, temp);
                }
            }
            data[x][y] = 0;
        }
        return;
    }

    //位置(x, y)上有无障碍物：
    public static boolean is_block(int y, int x, byte[][] data) {
        if (data[y][x] == 0) {
            return false;
        }
        return true;
    }

    //水平检测
    public static boolean horizon(int y1, int x1, int y2, int x2, byte[][] data) {
        if (y1 == y2 && x1 != x2) {
            int startX = Math.min(x1, x2);
            int endX = Math.max(x1, x2);
            for (int i = startX + 1; i < endX; i++) {
                if (is_block(y1, i, data)) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }

    //垂直检测
    public static boolean vertical(int y1, int x1, int y2, int x2, byte[][] data) {
        if (y1 != y2 && x1 == x2) {
            int startY = Math.min(y1, y2);
            int endY = Math.max(y1, y2);
            for (int i = startY + 1; i < endY; i++) {
                if (is_block(i, x1, data)) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }

    //一个拐角检测
    public static boolean turn_once(int y1, int x1, int y2, int x2, byte[][] data) {
        if (y1 == y2 && x1 == x2) {
            return false;
        }
        //C点
        int c_y = y1;
        int c_x = x2;
        if (!is_block(c_y, c_x, data)) {
            if (horizon(y1, x1, c_y, c_x, data) && vertical(c_y, c_x, y2, x2, data)) {
                return true;
            }
        }
        //D点
        int d_y = y2;
        int d_x = x1;
        if (!is_block(d_y, d_x, data)) {
            if (vertical(y1, x1, d_y, d_x, data) && horizon(d_y, d_x, y2, x2, data)) {
                return true;
            }
        }
        return false;
    }

    //两个拐角检测 == 一个拐角检测 && (水平检测 || 垂直检测)
    public static boolean turn_twice(int y1, int x1, int y2, int x2, byte[][] data) {
        if (y1 == y2 && x1 == x2) {
            return false;
        }

        for (int i = 0; i < 11; i++) {
            for (int j = 0; j < 19; j++) {
                //水平、垂直分别穿过 A B 共有四条直线，扫描直线上所有不包含 A B 的点，看是否存在一点 C
                if ((i != y1 && i != y2 && j != x1 && j != x2)) {
                    continue;
                }
                if ((i == y1 && j == x1) || (i == y2 && j == x2)) //不是A或B点
                {
                    continue;
                }
                if (is_block(i, j, data)) {
                    continue;
                }
                if (turn_once(y1, x1, i, j, data) && (horizon(i, j, y2, x2, data) || vertical(i, j, y2, x2, data))) {
                    return true;
                }
                if (turn_once(y2, x2, i, j, data) && (horizon(i, j, y1, x1, data) || vertical(i, j, y1, x1, data))) {
                    return true;
                }
            }
        }
        return false;
    }

    //判断两个点是否可以消除
    public static int can_remove(int y1, int x1, int y2, int x2, byte[][] data) {
        if (horizon(y1, x1, y2, x2, data)) {
            return 1;
        }
        if (vertical(y1, x1, y2, x2, data)) {
            return 2;
        }
        if (turn_once(y1, x1, y2, x2, data)) {
            return 3;
        }
        if (turn_twice(y1, x1, y2, x2, data)) {
            return 4;
        }
        return 0;
    }

}
